package com.pac.weixin.controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.common.tools.StringTools;
import com.common.util.PropertyUtils;
import com.kuanrf.commons.weixin.api.WxService;
import com.kuanrf.commons.weixin.api.help.WxMsgRouter;
import com.kuanrf.commons.weixin.bean.WxJsapiSignature;
import com.kuanrf.commons.weixin.common.WxConfigStorage;
import com.kuanrf.commons.weixin.exception.WxErrorException;
import com.kuanrf.commons.weixin.msg.bean.WxMsg;
import com.kuanrf.commons.weixin.msg.bean.result.WxOAuth2AccessToken;
import com.kuanrf.commons.weixin.msg.reply.bean.BaseReplyMsg;
import com.pac.doctor.service.DoctorService;
import com.pac.user.bean.UserDetailBean;
import com.pac.user.service.UserDetailService;
import com.pac.weixin.WeiXinKeyContent;
import com.pac.weixin.service.WeiXinService;
import com.pac.weixin.service.WxChatService;
import com.pac.weixin.service.WxUserService;

/**
 * 微信入口
 * 
 * @author lujun.chen
 * @version [版本号, 2015年2月15日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Controller
@Scope("prototype")
@RequestMapping("/weixin")
public class WxController {

	private static Logger logger = Logger.getLogger(WxController.class);

	@Autowired
	private WeiXinService weiXinService;

	@Autowired
	private WxChatService wxChatService;

	@Autowired
	private UserDetailService userDetailService;

	@Autowired
	private DoctorService doctorService;

	@Autowired
	private WxUserService wxUserService;

	@Autowired
	private WxService wxMpService;

	@Autowired
	private WxMsgRouter wxMpMessageRouter;

	@Autowired
	private WxConfigStorage wxMpConfigStorage;

	/**
	 * 微信首页
	 * 
	 * @param request
	 * @param openId
	 * @param signature
	 * @param timestamp
	 * @param nonce
	 * @param echostr
	 * @return
	 * @throws IOException
	 * @see [类、类#方法、类#成员]
	 */
	@RequestMapping("")
	public void index(HttpServletRequest request, HttpServletResponse response)
			throws IOException {

		PrintWriter out = response.getWriter();
		response.setContentType("text/html;charset=utf-8");
		response.setStatus(HttpServletResponse.SC_OK);

		String signature = request.getParameter("signature");
		String nonce = request.getParameter("nonce");
		String timestamp = request.getParameter("timestamp");

		if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
			// 消息签名不正确，说明不是公众平台发过来的消息
			out.print("非法请求");
			return;
		}

		String echostr = request.getParameter("echostr");
		if (StringUtils.isNotBlank(echostr)) {
			// 说明是一个仅仅用来验证的请求，回显echostr
			out.print(echostr);
			return;
		}

		String encryptType = StringUtils.isBlank(request
				.getParameter("encrypt_type")) ? "raw" : request
				.getParameter("encrypt_type");

		if ("raw".equals(encryptType)) {
			// 明文传输的消息
			WxMsg inMessage = WxMsg.fromXml(request.getInputStream());
			BaseReplyMsg outMessage = wxMpMessageRouter.route(inMessage);
			if (outMessage != null) {
				out.print(outMessage.toXml());
			}
			return;
		} else if ("aes".equals(encryptType)) {
			// 是aes加密的消息
			String msgSignature = request.getParameter("msg_signature");
			WxMsg inMessage = WxMsg.fromEncryptedXml(request.getInputStream(),
					wxMpConfigStorage, timestamp, nonce, msgSignature);
			BaseReplyMsg outMessage = wxMpMessageRouter.route(inMessage);
			if (outMessage != null) {
				out.print(outMessage.toEncryptedXml(wxMpConfigStorage));
			}
			return;
		}
		out.print("不可识别的加密类型");
		return;

	}

	/**
	 * 微信 验证服务器地址的有效性
	 * 
	 * 开发者提交信息后，微信服务器将发送GET请求到填写的服务器地址URL上，GET请求携带四个参数：
	 * 
	 * @param signature
	 *            微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
	 * @param timestamp
	 *            时间戳
	 * @param nonce
	 *            随机数
	 * @param echostr
	 *            随机字符串
	 * @return
	 * @see [类、类#方法、类#成员]
	 */
	public boolean checkSignature(String signature, String timestamp,
			String nonce, String echostr) {

		List<String> tmpArr = new ArrayList<String>();
		tmpArr.add(WeiXinKeyContent.WEIXIN_TOKEN);
		tmpArr.add(timestamp);
		tmpArr.add(nonce);
		Collections.sort(tmpArr);
		String tmpStr = tmpArr.toString();
		tmpStr = String.valueOf(DigestUtils.sha1(tmpStr));
		if (tmpStr.equals(signature)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 微信登陆
	 * 
	 * 检查该微信openId是否已经在系统注册，如果没有注册就先让用户完善个人资料， 完善用户资料后再跳转到微信主页
	 * 
	 * @param request
	 * @param openId
	 * @return
	 * @throws WxErrorException
	 * @see [类、类#方法、类#成员]
	 */
	@RequestMapping("/index")
	public ModelAndView login(HttpServletRequest request, String openId)
			throws WxErrorException {

		ModelAndView mov = new ModelAndView();

		String appId = "";
		String timestamp = "";
		String nonceStr = "";
		String signature = "";
		String wxCode = "";

		WxOAuth2AccessToken autoToken = null;

		try {
			// 如果微信菜单直接跳转，先从微信服务器获取openid
			if (StringTools.isNull(openId)) {
				Map<String, String[]> map = request.getParameterMap();
				wxCode = map.get("code")[0];
				// 通过微信网页授权code换取accessToke和openId
				autoToken = wxMpService.oauth2getAccessToken(wxCode);
				openId = autoToken.getOpenId();

				// 微信页面获取js-sdk授权
				String url = PropertyUtils.getValue("system.domain.url")
						+ "/weixin/index?";
				Set<String> keysets = map.keySet();
				for (String key : keysets) {
					String paramV = map.get(key)[0];
					paramV = URLEncoder.encode(paramV, "UTF-8");
					url += key + "=" + paramV + "&";
				}
				url = url.substring(0, url.length() - 1);
				appId = PropertyUtils.getValue("weixin.appID");
				// 获取微信js授权签名
				WxJsapiSignature jsSign = wxMpService.createJsapiSignature(url);

				timestamp = String.valueOf(jsSign.getTimestamp());
				nonceStr = jsSign.getNoncestr();
				signature = jsSign.getSignature();
			}
		} catch (Exception ex) {
			logger.error("进入微信选择医生页面出错，" + ex);
		}
		
		// 检查是否填写明细信息，如果未填写用户明细信息，就进入注册页面
		UserDetailBean userDetail = userDetailService
				.findUserDetailByOpenId(openId);
		if (null == userDetail) {
			try {
				weiXinService.wxUserinfo(autoToken);
			} catch (Exception ex) {
				logger.error("获取微信用户信息出错，" + ex);
			}
			mov.setViewName("/weixin/register/register");
		} else {
			// 进入选择医院界面
			mov.setViewName("/weixin/hospital/hospitalSel");
		}

		mov.addObject("openId", openId);

		mov.addObject("appId", appId);
		mov.addObject("timestamp", timestamp);
		mov.addObject("nonceStr", nonceStr);
		mov.addObject("signature", signature);

		return mov;
	}

	/**
	 * 进入微信注册页面
	 * 
	 * @param request
	 * @return
	 * @see [类、类#方法、类#成员]
	 */
	@RequestMapping("/register")
	public ModelAndView register(HttpServletRequest request) {

		String openId = "";
		try {
			// 解析微信端穿过来的参数
			Map<String, String[]> map = request.getParameterMap();
			String wxCode = map.get("code")[0];
			// 通过微信网页授权code换取accessToke和openId

			WxOAuth2AccessToken autoToken = wxMpService
					.oauth2getAccessToken(wxCode);

			openId = autoToken.getOpenId();
		} catch (Exception ex) {
			logger.error("进入微信注册页面出错，" + ex);
		}

		// 获取用户明细
		UserDetailBean userdetail = userDetailService
				.findUserDetailByOpenId(openId);

		if (null == userdetail) {
			userdetail = new UserDetailBean();
		}

		ModelAndView mov = new ModelAndView();
		mov.setViewName("/weixin/register/register");
		mov.addObject("openId", openId);
		mov.addObject("userdetail", userdetail);

		return mov;
	}

	/**
	 * @return
	 * @see [类、类#方法、类#成员]
	 */
	@RequestMapping("/gotopage")
	public ModelAndView gotopage(HttpServletRequest request, String pagename) {

		ModelAndView mov = new ModelAndView();
		String appId = "";
		String timestamp = "";
		String nonceStr = "";
		String signature = "";

		try {
			Map<String, String[]> map = request.getParameterMap();

			// 微信页面获取js-sdk授权
			String url = PropertyUtils.getValue("system.domain.url")
					+ "/weixin/gotopage?";
			Set<String> keysets = map.keySet();
			for (String key : keysets) {
				String paramV = map.get(key)[0];
				paramV = URLEncoder.encode(paramV, "UTF-8");
				url += key + "=" + paramV + "&";
				mov.addObject(key, paramV);
			}
			url = url.substring(0, url.length() - 1);
			appId = PropertyUtils.getValue("weixin.appID");
			// 获取微信js授权签名

			WxJsapiSignature jsSign = wxMpService.createJsapiSignature(url);

			timestamp = String.valueOf(jsSign.getTimestamp());
			nonceStr = jsSign.getNoncestr();
			signature = jsSign.getSignature();
		} catch (Exception ex) {
			logger.error("微信页面跳转出错，" + ex);
		}

		if (!StringTools.isNull(pagename)) {
			pagename = pagename.replace("_", "/");
		}

		mov.setViewName("/weixin/" + pagename);

		mov.addObject("appId", appId);
		mov.addObject("timestamp", timestamp);
		mov.addObject("nonceStr", nonceStr);
		mov.addObject("signature", signature);

		return mov;
	}

}
